﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KC.DataAccess.MV6;
using KC.ExtensionMethods;

namespace KC.Business.Blog
{
	public static class Search
	{
		public static List<string> SearchBlog(string input)
		{
			if (string.IsNullOrEmpty(input)) throw new ArgumentNullException("input");
			string[] parts = input.Split(new char[] { ' ', '\t', '\r', '\n', '\'' });
			MV6DataContext dc = new MV6DataContext();
			List<string> output = new List<string>();
			int CurIdx = 1;

			foreach (int PostID in utils.SearchPosts(parts))
			{
				output.Add(GetPostReturnHtml(ref dc, input, PostID, CurIdx));
				CurIdx++;
			}

			foreach (int ArticleID in utils.SearchArticles(parts))
			{
				output.Add(GetArticleReturnHtml(ref dc, input, ArticleID, CurIdx));
				CurIdx++;
			}

			foreach (int CommentID in utils.SearchComments(parts))
			{
				output.Add(GetCommentReturnHtml(ref dc, input, CommentID, CurIdx));
				CurIdx++;
			}

			return output;
		}
		private static string GetPostReturnHtml(ref MV6DataContext dc, string query, int PostID, int index)
		{
			char[] splitchars = new char[] { '\'', ';', ':', '\"', '<', ',', '.', '>', '/', '?', ' ', '\t', '\r', '\n' };
			string[] parts = query.Split(splitchars);

			var posts = from p2 in dc.Posts where p2.ID == PostID select p2;
			if (posts.Count() != 1)
			{
				Logging.Logger.Write("KC Architecture", "Wrong qty posts with ID " + PostID.ToString() + ": " + posts.Count().ToString(), null, Logging.Logger.Severity.Error);
				return null;
			}
			Post p = posts.First();

			string url = "Post.aspx?ID=" + PostID.ToString();
			string Title = p.Title;
			string type = "<a href=\".\">Post</a>";
			DateTime dt = p.Created;

			// Extract Excerpt and build return HTML
			string Excerpt = ExtractExcerpt(parts, p.Body);
			return BuildReturnHtml(query, url, Title, Excerpt, type, dt, index);
		}

		private static string GetArticleReturnHtml(ref MV6DataContext dc, string query, int ArticleID, int index)
		{
			char[] splitchars = new char[] { '\'', ';', ':', '\"', '<', ',', '.', '>', '/', '?', ' ', '\t', '\r', '\n' };
			string[] parts = query.Split(splitchars);

			var arts = from a2 in dc.Articles where a2.ID == ArticleID select a2;
			if (arts.Count() != 1)
			{
				Logging.Logger.Write("KC Architecture", "Wrong qty Articles with ID " + ArticleID.ToString() + ": " + arts.Count().ToString(), null, Logging.Logger.Severity.Error);
				return null;
			}
			Article a = arts.First();

			string url = "Articles.aspx?ID=" + a.ID.ToString();
			string Title = a.Title;
			string type = "<a href=\"Articles.aspx\">Article</a>";
			DateTime dt = a.Created;

			// Extract Excerpt and build return HTML
			string Excerpt = ExtractExcerpt(parts, a.Body);
			return BuildReturnHtml(query, url, Title, Excerpt, type, dt, index);
		}
		private static string GetCommentReturnHtml(ref MV6DataContext dc, string query, int CommentID, int index)
		{
			char[] splitchars = new char[] { '\'', ';', ':', '\"', '<', ',', '.', '>', '/', '?', ' ', '\t', '\r', '\n' };
			string[] parts = query.Split(splitchars);

			var comms = from a2 in dc.Comments where a2.ID == CommentID select a2;
			if (comms.Count() != 1)
			{
				Logging.Logger.Write("KC Architecture", "Wrong qty Comments with ID " + CommentID.ToString() + ": " + comms.Count().ToString(), null, Logging.Logger.Severity.Error);
				return null;
			}
			Comment comm = comms.First();

			string url = "Comments.aspx?ID=" + comm.ID.ToString();
			string Title = comm.Body;
			if (comm.Body.Length > 75) comm.Body = comm.Body.Substring(0, 70) + "<b>...</b>";
			string type = "<a href=\".\">Comment</a>";
			DateTime dt = comm.DateTime;

			// Extract Excerpt and build return HTML
			string Excerpt = ExtractExcerpt(parts, comm.Body);
			return BuildReturnHtml(query, url, Title, Excerpt, type, dt, index);
		}
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
		public static string ExtractExcerpt(string[] parts, string body)
		{
			if (parts == null) throw new ArgumentNullException("parts");
			if (string.IsNullOrEmpty(body)) throw new ArgumentNullException("body");

			int start = 0, stop = 0;
			body = System.Text.RegularExpressions.Regex.Replace(
				body
					.ToLower()
					.Replace("!notruncate", "")
					.Trim()
					.Replace("[[", "<")
					.Replace("]]", ">")
					.Replace("<br>", " ")
					.Replace("<br />", " "),
				@"<.*?>", "[[b]]...[[/b]]");

			while (body.Contains("[[b]]...[[/b]]") || body.Contains("  ") || body.Contains("......"))
			{
				while (body.Contains("[[b]]...[[/b]][[b]]...[[/b]]"))
					body = body.Replace("[[b]]...[[/b]][[b]]...[[/b]]", "[[b]]...[[/b]]");

				body = System.Text.RegularExpressions.Regex.Replace(
					body
						.Replace("[b]]", "[[b]]")
						.Replace("[[[b]]", "[[b]]"),
						@"<.*?>", " ")
					.Replace("[[", "<")
					.Replace("]]", ">")
					.Replace("... ", "...");
				while (body.Contains("......")) body = body.Replace("......", "...");
				while (body.Contains("  ")) body = body.Replace("  ", " ");
				while (body.Contains("<b>...</b> <b>...</b>")) body = body.Replace("<b>...</b> <b>...</b>", "<b>...</b>");
			}

			// Set the excerpt starting position to the first instance of one of the searched words
			for (int i = 0; i < body.Length; i++)
				foreach (string word in parts)
					if (body.Substring(i).StartsWith(word.ToLower()) && start == 0)
						start = i;
			start -= 20;
			if (start < 0) start = 0;

			// Set excerpt stop position
			stop = start + 500;
			if (stop > body.Length) stop = body.Length;
			if (stop < start) start = 0;

			// Don't get stuck inside an HTML Tag: Pan back to the most recent [[ or ]] code, if one happened recently, but only to the extent that a query term is still contained therein
			while (body.Substring(start, ((stop - start - 25) > start ? (stop - start - 25) : stop - start)).ContainsAny(parts) && (
				(!body.Substring(start).StartsWith("[[") && !body.Substring(start).StartsWith("]]") && start > 0) ||
				(!body.Substring(start).StartsWith("<") && !body.Substring(start).StartsWith(">") && start > 0)))
				start--;
			if (body.Substring(start).StartsWith("]]")) start += 2;
			else if (body.Substring(start).StartsWith(">")) start++;

			// reset excerpt stop position
			stop = start + 500;
			if (stop > body.Length) stop = body.Length;
			if (stop < start) start = 0;

			string Excerpt = body.Substring(start, stop - start);

			// Don't get stuck inside an HTML Tag: Pan the end up to the next [[ code, or the next ]] code plus two
			while (stop < body.Length && !Excerpt.EndsWithAny(new string[] { "<", ">", "[[", "]]" }))
			{
				stop++;
				Excerpt = body.Substring(start, stop - start);
				if (Excerpt.EndsWith(">"))
				{
					stop++;
					Excerpt = body.Substring(start, stop - start);
					break;
				}
				if (Excerpt.EndsWith("]]"))
				{
					stop += 2;
					Excerpt = body.Substring(start, stop - start);
					break;
				}
				if (Excerpt.EndsWithAny(new string[] { "<", "[[" }))
				{
					Excerpt = Excerpt.Substring(0, Excerpt.Length - 1);
					break;
				}
			}

			if (start > 0) Excerpt = "<b>...</b>" + Excerpt;
			if (stop < body.Length - 1) Excerpt += "<b>...</b>";

			return Excerpt;
		}
		private static string BuildReturnHtml(string query, string url, string title, string excerpt, string type, DateTime dt, int index)
		{
			char[] splitchars = new char[] { '\'', ';', ':', '\"', ',', '.', '/', '?', ' ', '\t', '\r', '\n' };
			string[] QueryWords = System.Text.RegularExpressions.Regex.Replace(query, @"<.*?>", " ").ToLower().Split(splitchars);

			foreach (string QueryWord in QueryWords)
			{
				title = title.Replace(QueryWord, "<b>" + QueryWord + "</b>");
				excerpt = excerpt.Replace(QueryWord, "<b>" + QueryWord + "</b>");
			}

			string output =
				"<h3>" + index.ToString() + ": <a href=\"" + url + "\">" + title + "</a></h3>" +
				excerpt +
				"</b><br /><cite>" + url + "</cite>\r\n" +
				"<span class=gl> - " + type + " - &nbsp;&nbsp;" +
				"<a href=\"archives.aspx?Min=" + dt.ToString("MM/dd/yyyy") + "\">" + dt.ToString("MM/dd/yyyy HH:mm:ss") + "</a></span>";
			while (excerpt.Contains("  ")) excerpt = excerpt.Replace("  ", " ");
			return output;
		}
	}
}
